package com.hcl.orm.core.dialect.handler.func;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.hcl.orm.core.annotation.DBType;
import com.hcl.orm.core.dialect.SqlDefinition;
import org.springframework.stereotype.Component;

import java.util.List;

import static com.hcl.orm.core.exception.ParamAssert.checkHsFunctionParam;

/**
 * @author hucl
 * @projectName hcl-orm
 * @description: Mysql函数翻译
 * @date 2021/8/1114:20
 */
@Component
public class MysqlFuncDialectHandler extends FuncDialectHandler {

    public MysqlFuncDialectHandler() {
        super("Mysql SQL函数方言处理器");
    }

    /**
     * 函数的转换，只需要对标准SQL进行处理即可
     *
     * @param sqlDefinition
     */
    @Override
    protected void doHandle(SqlDefinition sqlDefinition) {
        if (StrUtil.isEmpty(sqlDefinition.getRawSql())) {
            return;
        }
        List<String> funStrList = extractFuncStr(sqlDefinition.getRawSql());
        String dialectSqlTmpl = sqlDefinition.getRawSql();
        for (int i = 0; i < funStrList.size(); i++) {
            final String funcExpression = funStrList.get(i);
            final String funcName = extractFuncName(funcExpression);
            switch (funcName) {
                case FUNC_HS_ADD_DAY: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs, 2);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("date_add({}, INTERVAL {} DAY)", inputs.get(0), inputs.get(1)));
                    break;
                }
                case FUNC_HS_ADD_MONTH: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("date_add(sysdate(), INTERVAL {} MONTH)", inputs.get(1)));
                    break;
                }
                case FUNC_HS_TIME_FORMAT: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs, 1);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("time_format({},'%H-%i-%S')", inputs.get(0)));
                    break;
                }
                case FUNC_HS_CEIL: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs, 1);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("ceiling({})/ceil({}))", inputs.get(0), inputs.get(0)));
                    break;
                }
                case FUNC_HS_DATE_FORMAT: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs, 3);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("date_format({},{})", inputs.get(0), inputs.get(1)));
                    break;
                }
                case FUNC_HS_DATE_INT: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            "cast(DATE_FORMAT(NOW(),'%Y%m%d') AS SIGNED INTEGER)");
                    break;
                }
                case FUNC_HS_NUMBER: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs, 1);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("cast({} as signed integer)", inputs.get(0)));
                    break;
                }
                case FUNC_HS_TO_DATE: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs, 3);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("str_to_date({},{})"
                                    , inputs.get(0), inputs.get(1)));
                    break;
                }
                case FUNC_HS_TIMESTAMP_INT: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            "round(cast(DATE_FORMAT(NOW(),'%H%i%s%f') AS SIGNED INTEGER) /1000)");
                    break;
                }
                case FUNC_HS_ROWNUM: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            "row_number()over()");
                    break;
                }
                case FUNC_HS_DATETIME_INT: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs, 2);
                    if (inputs.get(1).equalsIgnoreCase("YYYYMMDD")) {
                        dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                                StrUtil.format("cast(DATE_FORMAT({},'%Y%m%d') AS SIGNED INTEGER)"
                                        , inputs.get(0)));
                    } else if (inputs.get(1).equalsIgnoreCase("HH24MISS")) {
                        dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                                StrUtil.format("cast(DATE_FORMAT({},'%H%i%s') AS SIGNED INTEGER)"
                                        , inputs.get(0)));
                    }
                    break;
                }
                default: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcName,
                            super.replaceCommonFunc(funcName));
                    break;
                }
            }
        }
        sqlDefinition.setDialectSql(dialectSqlTmpl);
    }

    @Override
    protected List<DBType> getTargetDB() {
        return ListUtil.toList(DBType.MYSQL, DBType.OB_MYSQL);
    }
}
